package cate.game.role.res.guild.po.fairyland.core;

import cate.common.table.d.GDFunc;
import cate.common.table.d.GDGuild;
import cate.common.table.d.GDOperation;
import cate.common.table.guild.fairyland.base.GuildFairyBaseRow;
import cate.common.table.guild.fairyland.buff.GuildFairylandBuffRow;
import cate.common.table.guild.treasurehouse.core.RandomTreasureItem;
import cate.common.table.guild.treasurehouse.core.TreasureItem;
import cate.common.util.GameResult;
import cate.common.util.random.RWList;
import cate.game.GameBody;
import cate.game.mail.po.MailBuilder;
import cate.game.play.proce.play.PlayPO;
import cate.game.res.MixRes;
import cate.game.res.Pair;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import cate.game.role.farm.guildFairyland.GuildFairylandFTC;
import cate.game.role.mail.Mail;
import cate.game.role.res.guild.po.GuildPO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.annotation.Transient;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@NoArgsConstructor
@NoteClass("公会秘境单个BOSS数据")
public class GuildFairylandBossPO {
    @NoteField("BOSS类别")
    public int bossType;
    @NoteField("BOSS等级")
    public int bossLevel;
    @NoteField("BOSS当前血量")
    public long curHp;
    @NoteField("BUFF列表")
    public List<Integer> buffs;
    @NoteField("当前状态")
    public int state;
    @NoteField("当前排行")
    public List<GuildFairyRank> rankList;

    @Transient
    @JsonIgnore
    private GameBody game;
    @Transient
    @JsonIgnore
    private GuildPO guild;

    public GuildFairylandBossPO(GameBody game, int bossId) {
        this.game = game;
        this.bossType = bossId;
        this.bossLevel = 1;
        this.curHp = Optional.ofNullable(getBaseRow()).map(row -> row.hp).orElse(0L);
        this.rankList = new ArrayList<>();
    }

    public void initialize(GuildPO guild) {
        this.game = guild.game;
        this.guild = guild;
        if (rankList == null) {
            rankList = new ArrayList<>();
        }
        if (buffs == null) {
            buffs = new ArrayList<>();
        }
    }

    /**
     * 获取基础配置
     */
    @JsonIgnore
    public GuildFairyBaseRow getBaseRow() {
        return game.table.guildFairyland.base.getList().stream()
                .filter(row -> row.bossType == bossType && row.bossLevel == bossLevel)
                .findAny()
                .orElse(null);
    }

    /**
     * 获取基础配置
     */
    @JsonIgnore
    public GuildFairyBaseRow getBaseRow(int level) {
        return game.table.guildFairyland.base.getList().stream()
                .filter(row -> row.bossType == bossType && row.bossLevel == level)
                .findAny()
                .orElse(null);
    }

    /**
     * 挑战BOSS
     *
     * @param role 玩家
     * @return 挑战结果 携带数据是否为追击
     */
    public EcResult<Boolean> challenge(Role role) {
        EcResult<Boolean> r = new EcResult<>();
        GuildFairyBaseRow baseRow = getBaseRow();
        if (baseRow == null) {
            return r.fail("配置出错");
        }
        r.data = curHp <= 0;
        if (r.data) {
            updateDamageRank(role, 0L);
            return r.success();
        }
        // 构建挑战阵容
        EcResult<Pair<GuildFairylandFTC, PlayPO>> r_fight = role.getFarm().guildFairyland.startFight(baseRow.id, buffs, curHp);
        if (!r_fight.ok()) {
            return r.fail(r_fight.code, r_fight.message);
        }
        long damage = r_fight.data.v.teamEnd.b.getAllHero().get(0).performance.hurt;
        r_fight.data.k.damage = damage;
        curHp = Math.max(0, curHp - damage);
        // 判断击杀
        if (curHp <= 0) {
            r_fight.data.k.killed = true;
            // 发放击杀奖励
            Mail kMail = new MailBuilder().setReward(new MixRes(baseRow.killReward))
                    .setContentId(GDGuild.Fairyland.KILL_MAIL_ID)
                    .setOperation(GDOperation.GUILD_FAIRYLAND_KILL)
                    .setOperationSub(baseRow.id)
                    .build();
            game.mail.send(role, kMail);
            // 宝库奖励
            List<TreasureItem> treasures = baseRow.stableTreasureItems.stream().map(TreasureItem::copy).collect(Collectors.toList());
            RWList<RandomTreasureItem> rwList = new RWList<>(baseRow.randomTreasureItems.stream().map(RandomTreasureItem::copy).collect(Collectors.toList()));
            for (int i = 0; i < baseRow.randomTreasureNum; i++) {
                if (rwList.isEmpty()) {
                    break;
                }
                rwList.setup();
                RandomTreasureItem randomItem = rwList.get();
                if (randomItem == null) {
                    break;
                }
                treasures.add(randomItem.ti);
                rwList.list.remove(randomItem);
            }
            // 将奖励放入公会宝库
            treasures.forEach(item -> {
                GameResult<MixRes> r_put = guild.treasureHouse.putTreasureIn(null, item.tid, item.num, GDFunc.GuildFunc.FAIRYLAND);
                if (!r_put.ok()) {
                    log.error("[公会秘境BOSS] 添加宝库奖励失败! {}", item);
                }
            });
        }
        // 更新伤害
        updateDamageRank(role, damage);
        return r.success();
    }

    /**
     * 更新玩家伤害
     *
     * @param role   玩家
     * @param damage 伤害值
     */
    private void updateDamageRank(Role role, long damage) {
        Optional<GuildFairyRank> op = rankList.stream().filter(rank -> role.getUid().equals(rank.owner.uid)).findAny();
        if (op.isPresent()) {
            GuildFairyRank rank = op.get();
            rank.owner.read(role);
            rank.value += damage;
            if (damage > 0) {
                rank.recordTime = System.currentTimeMillis();
            }
        } else {
            GuildFairyRank rank = new GuildFairyRank();
            rank.owner = new RoleSnapshot(role);
            rank.value = damage;
            rank.recordTime = System.currentTimeMillis();
            rankList.add(rank);
        }
        rankList.sort(Comparator.comparing(GuildFairyRank::getValue)
                .reversed()
                .thenComparing(GuildFairyRank::getRecordTime));
    }

    /**
     * 开启挑战
     *
     * @return 开启结果
     */
    public EcResult<Void> open() {
        EcResult<Void> r = new EcResult<>();
        if (state == GuildFairylandState.CHALLENGE) {
            return r.fail("秘境已经开启");
        }
        int newLevel;
        if (curHp > 0) {
            // 上期没打死 等级减1
            newLevel = Math.max(1, bossLevel - 1);
        } else {
            // 上期打死了 等级加1
            newLevel = Math.min(game.table.guildFairyland.base.getMaxLevel(bossType), bossLevel + 1);
        }
        GuildFairyBaseRow baseRow = getBaseRow(newLevel);
        if (baseRow == null) {
            return r.fail("找不到BOSS基础配置了");
        }
        int activeCost = baseRow.activeCost;
        if (!guild.active.reduceActive(activeCost)) {
            return r.fail("公会活跃度不足");
        }
        bossLevel = newLevel;
        curHp = baseRow.hp;
        state = GuildFairylandState.CHALLENGE;
        buffs.clear();
        rankList.clear();
        if (baseRow.buffNum > 0) {
            RWList<GuildFairylandBuffRow> list = new RWList<>(game.table.guildFairyland.buff.getList());
            for (int i = 0; i < baseRow.buffNum; i++) {
                if (list.isEmpty()) {
                    break;
                }
                list.setup();
                GuildFairylandBuffRow buffRow = list.get();
                if (buffRow == null) {
                    break;
                }
                buffs.add(buffRow.buffId);
                list.list.remove(buffRow);
            }
        }
        return r.success();
    }
}
